import 'dart:math';

import 'package:flutter/material.dart';

/// 可以整体或局部适配，使用尺寸时需要进行换算。
///
/// 非svg的图片缩放后可能会模糊。
class ScreenAdaptBuilder extends StatelessWidget {
  /// 设计稿尺寸
  final double? width;
  final double? height;

  /// 获取[ScreenAdaptExt.size]时是否基于宽度/高度/最小值/最大值缩放。
  /// 默认值为[ScreenAdaptSizeBy.min]
  final ScreenAdaptSizeBy sizeBy;

  /// 控制字体是否要根据系统的“字体大小”辅助选项来进行缩放。默认值为false。
  final bool allowFontScaling;

  final WidgetBuilder builder;

  const ScreenAdaptBuilder(
      {Key? key,
      this.width,
      this.height,
      required this.builder,
      this.sizeBy = ScreenAdaptSizeBy.min,
      this.allowFontScaling = false})
      : assert(width != null || height != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraint) {
      final mediaQuery = MediaQuery.of(context);
      final size = constraint.isTight
          ? constraint.biggest
          : constraint.constrain(mediaQuery.size);
      final width = this.width ?? this.height! * size.width / size.height;
      final height = this.height ?? this.width! / size.width * size.height;
      final scaleWidth = size.width / width;
      final scaleHeight = size.height / height;

      var screenAdaptData = ScreenAdaptData(
          scaleWidth: scaleWidth,
          scaleHeight: scaleHeight,
          textScaleFactor: mediaQuery.textScaleFactor,
          sizeBy: sizeBy,
          allowFontScaling: allowFontScaling);
      return ScreenAdapt(
          data: screenAdaptData, child: Builder(builder: builder));
    });
  }
}

class ScreenAdapt extends InheritedWidget {
  final ScreenAdaptData data;

  const ScreenAdapt({
    Key? key,
    required this.data,
    required Widget child,
  }) : super(key: key, child: child);

  @override
  bool updateShouldNotify(ScreenAdapt oldWidget) {
    return data != oldWidget.data;
  }

  static ScreenAdaptData? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<ScreenAdapt>()?.data;
  }
}

class ScreenAdaptData {
  final double scaleWidth;
  final double scaleHeight;
  final double textScaleFactor;
  final ScreenAdaptSizeBy sizeBy;
  final bool allowFontScaling;

  ScreenAdaptData(
      {required this.scaleWidth,
      required this.scaleHeight,
      required this.textScaleFactor,
      required this.sizeBy,
      required this.allowFontScaling});

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is ScreenAdaptData &&
          runtimeType == other.runtimeType &&
          scaleWidth == other.scaleWidth &&
          scaleHeight == other.scaleHeight &&
          textScaleFactor == other.textScaleFactor &&
          sizeBy == other.sizeBy &&
          allowFontScaling == other.allowFontScaling;

  @override
  int get hashCode =>
      scaleWidth.hashCode ^
      scaleHeight.hashCode ^
      textScaleFactor.hashCode ^
      sizeBy.hashCode ^
      allowFontScaling.hashCode;
}

enum ScreenAdaptSizeBy { width, height, min, max }

extension ScreenAdaptExt on num {
  /// 获取尺寸，根据配置选择按宽度还是高度缩放。
  double size(BuildContext context) {
    var data = ScreenAdapt.of(context)!;
    var scaleRatio = 1.0;
    switch (data.sizeBy) {
      case ScreenAdaptSizeBy.width:
        scaleRatio = data.scaleWidth;
        break;
      case ScreenAdaptSizeBy.height:
        scaleRatio = data.scaleHeight;
        break;
      case ScreenAdaptSizeBy.min:
        scaleRatio = min(data.scaleWidth, data.scaleHeight);
        break;
      case ScreenAdaptSizeBy.max:
        scaleRatio = max(data.scaleWidth, data.scaleHeight);
        break;
    }
    return scaleRatio * this;
  }

  /// 获取文字大小
  double sp(BuildContext context) {
    var data = ScreenAdapt.of(context)!;
    final textScaleFactor = data.allowFontScaling ? data.textScaleFactor : 1;
    return size(context) * textScaleFactor;
  }

  /// 根据设计宽度：屏幕宽度比例缩放
  double w(BuildContext context) => ScreenAdapt.of(context)!.scaleWidth * this;

  /// 根据设计高度：屏幕高度比例缩放
  double h(BuildContext context) => ScreenAdapt.of(context)!.scaleHeight * this;
}
